#ifndef __Logger__
#define __Logger__

#include"level.hpp"
#include"format.hpp"
#include"sink.hpp"
#include<mutex>
#include<atomic>
#include<cstdarg>
#include "looper.hpp"
#include "util.hpp"
#include<memory>
#include<unordered_map>
namespace log
{
    class Logger
    {
      public:
      using ptr = std::shared_ptr<Logger>;

      Logger(const std::string &logger_name,
      LogLevel::value level,
      Formatter::ptr &formatter,
      std::vector<LogSink::ptr> &sinks)
      :_logger_name(logger_name)
      ,_limit_level(level)
      ,_formatter(formatter)
      ,_sinks(sinks.begin(),sinks.end()){}
      const std::string& name(){return _logger_name;}
      //完成构造日志消息对象过程并进行格式化，得到格式化后的日志消息字符串--然后进行落地输出
      void debug(const std::string &file, size_t line, const std::string &fmt, ...)
      {
        //通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
        //1.判断当前的日志是否达到了输出等级
        //2.对fmt格式化字符串和不定参进行字符串组织，得到的日志消息的字符串
        //3.构造LogMsg对象
        //4.通过格式化工具对LogMsg进行格式化，得到格式化的日志字符串
        //5.进行日志落地

        //1. 判断当前的日志是否达到了输出等级
        if(LogLevel::value::DEBUG < _limit_level) {return ;}
        //2. 对fmt格式化字符串和不定参进行字符串组织，得到的日志消息的字符串 
        va_list ap; //参数列表指针
        va_start(ap, fmt);   //将fmt之后的第一个参数地址传给ap
        char *res;
        int ret = vasprintf(&res, fmt.c_str(), ap);
        if(ret == -1)
        {
          std::cout << "vasprintf is failed!!\n";
          return;
        }
        va_end(ap);//将ap指针置空
        serialize(LogLevel::value::DEBUG, file, line, res);
        free(res);


      }
      void info(const std::string &file, size_t line, const std::string &fmt, ...)
      {
        if(LogLevel::value::INFO < _limit_level) {return ;}
        //2. 对fmt格式化字符串和不定参进行字符串组织，得到的日志消息的字符串 
        va_list ap; //参数列表指针
        va_start(ap, fmt);   //将fmt之后的第一个参数地址传给ap
        char *res;
        int ret = vasprintf(&res, fmt.c_str(), ap);
        if(ret == -1)
        {
          std::cout << "vasprintf is failed!!\n";
          return;
        }
        va_end(ap);//将ap指针置空
        serialize(LogLevel::value::INFO, file, line, res);
        free(res);

      }

      void warn(const std::string &file, size_t line, const std::string &fmt, ...)
      {
        if(LogLevel::value::WARN < _limit_level) {return ;}
        //2. 对fmt格式化字符串和不定参进行字符串组织，得到的日志消息的字符串 
        va_list ap; //参数列表指针
        va_start(ap, fmt);   //将fmt之后的第一个参数地址传给ap
        char *res;
        int ret = vasprintf(&res, fmt.c_str(), ap);
        if(ret == -1)
        {
          std::cout << "vasprintf is failed!!\n";
          return;
        }
        va_end(ap);//将ap指针置空
        serialize(LogLevel::value::WARN, file, line, res);
        free(res);

      } 

      void error(const std::string &file, size_t line, const std::string &fmt, ...)
      {
        if(LogLevel::value::ERROR < _limit_level) {return ;}
        //2. 对fmt格式化字符串和不定参进行字符串组织，得到的日志消息的字符串 
        va_list ap; //参数列表指针
        va_start(ap, fmt);   //将fmt之后的第一个参数地址传给ap
        char *res;
        int ret = vasprintf(&res, fmt.c_str(), ap);
        if(ret == -1)
        {
          std::cout << "vasprintf is failed!!\n";
          return;
        }
        va_end(ap);//将ap指针置空
        serialize(LogLevel::value::ERROR, file, line, res);
        free(res);

      }

      void fatal(const std::string &file, size_t line, const std::string &fmt, ...)
      {
        if(LogLevel::value::FATAL < _limit_level) {return ;}
        //2. 对fmt格式化字符串和不定参进行字符串组织，得到的日志消息的字符串 
        va_list ap; //参数列表指针
        va_start(ap, fmt);   //将fmt之后的第一个参数地址传给ap
        char *res;
        int ret = vasprintf(&res, fmt.c_str(), ap); //申请空间，将组织好的字符串地址传给res
        if(ret == -1)
        {
          std::cout << "vasprintf is failed!!\n";
          return;
        }
        va_end(ap);//将ap指针置空
        serialize(LogLevel::value::FATAL, file, line, res);
        free(res);
      } 

      protected:
      void serialize(LogLevel::value level, const std::string &file, size_t line, char *str)
      {
        //3. 构造LogMsg对象
        LogMsg msg(line, level, file, _logger_name, str);
        //4.通过格式化工具对LogMsg进行格式化，得到格式化后的日志字符串
        std::stringstream ss;
        _formatter->format(ss,msg);
        //5. 进行日志落地
        log(ss.str().c_str(), ss.str().size());
 
      }

      //抽象接口完成实际的落地输出--不同的日志器会有不同的落地方式
      virtual void log(const char *data, size_t len) = 0;
      protected:
      std::mutex _mutex;//互斥锁 ：保证日志输出过程是线程安全的，不会交叉日志
      std::string _logger_name;
      std::atomic<LogLevel::value> _limit_level;
      Formatter::ptr _formatter;
      std::vector<LogSink::ptr> _sinks;//落地方式指针数组
        
    };

    class SyncLogger : public Logger  //同步日志器
    {
        public:
        SyncLogger
          (const std::string &logger_name,
            LogLevel::value level,
          Formatter::ptr &formatter,
          std::vector<LogSink::ptr> &sinks)
          :Logger(logger_name, level, formatter, sinks){}
          
         
      
        protected:
        void log(const char *data, size_t len)
        {
          std::unique_lock<std::mutex> lock(_mutex);
          if(_sinks.empty())return;
          for(auto &sink : _sinks)
          {
            sink->log(data,len);
          }
        }
    };

    class AsyncLogger : public Logger  // 异步日志器
    {
        public:
        AsyncLogger(const std::string &logger_name,
      LogLevel::value level,
      Formatter::ptr &formatter,
      std::vector<LogSink::ptr> &sinks,
      AsyncType looper_type)
      :Logger(logger_name, level, formatter, sinks)
      ,_looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), looper_type))
      {}
           //bind 将reallog函数重新实现，再传参的的时候不用传reallog本身的this指针，只需传自身的函数地址
//_looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), looper_type))

      void log(const char *data, size_t len)//将数据写入缓冲区
      {
          _looper->push(data, len);
      }

      void realLog(Buffer &buf)//设计一个实际落地函数（将缓冲区的数据落地）
      {
        if(_sinks.empty())
        return;
        for(auto &sink : _sinks)
        {
          sink->log(buf.begin(), buf.readAbleSize());
        }
      }
      private:
      AsyncLooper::ptr _looper;//异步工作器的指针
      

    };



    //使用建造者模式建造日志器，不要让用户自己先构造零件再建造出logger，简化用户的复杂度
    //1.抽象出一个日志器建造者类（完成日志器对象所需要零部件的构建以及日志器的构造）
    //  设置日志器类型
    //  将不同类型的日志器创建放在同一个日志器建造者类完成
    // 2.派生出具体的建造者类————局部建造者类和全局建造者类（后边添加了全局单例管理器后，将日志器添加全局管理）



    enum class LoggerType
    {
      LOGGER_SYNC,  //同步日志器类型
      LOGGER_ASYNC  //异步日志器类型
    };

    class LoggerBuilder
    {
      public:
      LoggerBuilder()
      :_logger_type(LoggerType::LOGGER_SYNC)
      ,_limit_level(LogLevel::value::DEBUG)
      ,_looper_type(AsyncType::ASYNC_SAFE)//异步工作器默认为安全模式
      {}
      void buildLoggerType(LoggerType type){_logger_type = type;}
      void buildEnableUnSafeAsync(){_looper_type = AsyncType::ASYNC_UNSAFE; }//异步工作器调用不安全模式
      void buildLoggerName(const::std::string &name){_logger_name = name;}
      void buildLoggerLevel(LogLevel::value level) {_limit_level = level;}
      void buildFommater(const std::string &pattern)
      {
        _formmater = std::make_shared<Formatter>(pattern);
      }

      template<typename SinkType, typename ...Args>
      void buildSink(Args &&...args)
      {
        LogSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
        _sinks.push_back(psink);
      }

      virtual Logger::ptr build() = 0;

      protected:
      AsyncType _looper_type;
      LoggerType _logger_type;
      std::string _logger_name;
      LogLevel::value _limit_level;
      Formatter::ptr _formmater;
      std::vector<LogSink::ptr> _sinks;

    };

    class LocalLoggerBuilder : public LoggerBuilder //局部建造者类  //在哪里创建就在哪里使用
    {
      public:
      Logger::ptr build() override
      {
        assert(_logger_name.empty()==false);
        if(_formmater.get() == nullptr)
        {
          _formmater = std::make_shared<Formatter>();
        }
        if(_sinks.empty())
        {
          buildSink<StdoutSink>();
        }
        if(_logger_type == LoggerType:: LOGGER_ASYNC )
        {
          return std::make_shared<AsyncLogger>(_logger_name,_limit_level, _formmater, _sinks, _looper_type);
        }
        return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formmater, _sinks);
      }
    };




      class LoggerManager//对所有创建的日志器进行管理
      {
        public:
        static LoggerManager& getInstance()//懒汉模式，需要时才创建单例对象
        {
          static LoggerManager eton;
          return eton;
        }
        void addLogger(Logger::ptr &logger)
        {
          if(hasLogger(logger->name())) { return ;}
          std::unique_lock<std::mutex> lock(_mutex);
          _loggers.insert(std::make_pair(logger->name(), logger));
        }

        bool hasLogger(const std::string &name)
        {
          std::unique_lock<std::mutex> lock(_mutex);
          auto it = _loggers.find(name);
          if(it == _loggers.end())
          {
              return false;
          }
          return true;
        }

        Logger::ptr getLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if(it == _loggers.end())
              return Logger::ptr(); //空指针

              return it->second;
        }

        Logger::ptr rootLogger()
        {
          return _root_logger;
        }
        private:
        LoggerManager()//构造函数
        {
          std::unique_ptr<log::LoggerBuilder> builder(new log::LocalLoggerBuilder());
          builder->buildLoggerName("root");
          _root_logger = builder->build(); //构造一个默认类型
          _loggers.insert(std::make_pair("root", _root_logger)); 
        }
        private:
        std::mutex _mutex;
        Logger::ptr _root_logger;//默认日志器
        std::unordered_map<std::string, Logger::ptr>  _loggers;
      };

      //设计一个全局日志器建造者--在局部的基础上增加了一个功能：将日志器添加到单例对象中

       class GlobalLoggerBuilder : public LoggerBuilder 
    {
      public:
      Logger::ptr build() override
      {
        assert(_logger_name.empty()==false);
        if(_formmater.get() == nullptr)
        {
          _formmater = std::make_shared<Formatter>();
        }
        if(_sinks.empty())
        {
          buildSink<StdoutSink>();
        }
        Logger::ptr logger;
        if(_logger_type == LoggerType:: LOGGER_ASYNC )
        {
          logger = std::make_shared<AsyncLogger>(_logger_name,_limit_level, _formmater, _sinks, _looper_type);
        }
        else logger = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formmater, _sinks);

        LoggerManager::getInstance().addLogger(logger);
        return logger; 
      }
    };


}



#endif